#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <cstring>
#include <functional>
#include <thread>
#include "Log.hpp"
#include <pthread.h>
#include <ctime>
#include "RingQueue.hpp"
#include "Task.hpp"
#include "udpUser.hpp"
#define PNUM 3
#define CNUM 5

enum
{
    SOCKET_ERR = 1,
    BIND_ERR
};
std::string defaultip = "0.0.0.0";
extern Log lg;
std::string opers = "+-*/%";
template <class T>
class RingQueueInfo
{
public:
    RingQueue<T> *rq_;
    std::string name_;
    int sockfd_;
};

// void *Producter(void *args)
// {
//     RingQueueInfo<Task> *info = (RingQueueInfo<Task> *)args;
//     int sockfd = info->sockfd_;
//     RingQueue<Task> *rq = info->rq_;
//     std::string name = info->name_;
 
//     char request[1024];
//     while (true)  
//     {
//         // 生产数据 -> 接受客户端message
//         struct sockaddr_in client;
//         int sockfd = info->sockfd_;
//         socklen_t len = sizeof(client);
//         bzero(&client, sizeof(client));
//         ssize_t n = recvfrom(sockfd, request, 1023, 0, (struct sockaddr *)&client, &len);
//         if(n < 0)
//         {
//             lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
//             continue;
//         }
//         Task t(request, client);
//         rq->Push(t);
//     }
//     delete info;
//     return nullptr;
// }

// void *Consumer(void *args)
// {
//     RingQueueInfo<Task> *info = (RingQueueInfo<Task> *)args;
//     int sockfd = info->sockfd_;
//     RingQueue<Task> *rq = info->rq_;
//     std::string name = info->name_;
//     while (true)
//     {
//         // 消费数据  -> 给客户端发送message
//         Task t = rq->Pop();
//         std::string response = "server echo# ";
//         response += t.message_;

//         std::cout << response << std::endl;
        
//         sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&(t.host_), sizeof(t.host_));
//     }
//     delete info;
//     return nullptr;
// }


class UdpServer
{
    using func_t = std::function<void(int, const std::string&, uint16_t, const std::string &)>;

public:
    UdpServer(func_t callback, const uint16_t& port, const std::string &ip = defaultip)
        : port_(port), ip_(ip), sockfd_(-1), isrunning_(false), callback_(callback)
    {
    }
    void init()
    {
        // create socket
        sockfd_ = socket(PF_INET, SOCK_DGRAM, 0);
        if (sockfd_ < 0)
        {
            lg(Fatal, "create socket error, sockfd: %d", sockfd_);
            exit(SOCKET_ERR);
        }
        lg(Info, "create socket success, sockfd: %d", sockfd_);

        // bind socket
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        // local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 1.string->int 2.htonl
        local.sin_addr.s_addr = INADDR_ANY;
        local.sin_port = htons(port_);
        socklen_t len = sizeof(local);
        if (bind(sockfd_, (const sockaddr *)&local, len) == -1)
        {
            lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));
            exit(BIND_ERR);
        }
        lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));
    }

    //基于环形队列的生产消费多线程版
    // void run()
    // {
    //     isrunning_ = true;
    //     char buffer[1024];
    //     srand(time(nullptr) ^ getpid());
    //     RingQueue<Task> *rq = new RingQueue<Task>();
    //     pthread_t p[PNUM], c[CNUM];

    //     for (int i = 0; i < PNUM; ++i)
    //     {
    //         RingQueueInfo<Task> *info = new RingQueueInfo<Task>();
    //         info->rq_ = rq;
    //         info->name_ = "pthread-" + std::to_string(i + 1);
    //         info->sockfd_ = sockfd_;
    //         pthread_create(p + i, nullptr, Producter, info);
    //     }
    //     for (int i = 0; i < CNUM; ++i)
    //     {
    //         RingQueueInfo<Task> *info = new RingQueueInfo<Task>();
    //         info->rq_ = rq;
    //         info->name_ = "cthread-" + std::to_string(i + 1);
    //         info->sockfd_ = sockfd_;
    //         pthread_create(p + i, nullptr, Consumer, info);
    //     }

    //     for (int i = 0; i < PNUM; ++i)
    //     {
    //         pthread_join(p[i], nullptr);
    //     }
    //     for (int i = 0; i < CNUM; ++i)
    //     {
    //         pthread_join(c[i], nullptr);
    //     }
    // }

    // 简易版
    void run()
    {
        isrunning_ = true;
        char buffer[1024];
        while(isrunning_)
        {
            //receive
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            bzero(&client, len);
            ssize_t n = recvfrom(sockfd_, buffer, 1023, 0, (struct sockaddr *)&client, &len);
            if(n < 0)
            {
                lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));
                continue;
            }
            std::string clientip = inet_ntoa(client.sin_addr);
            uint16_t clientport = ntohs(client.sin_port);

            //handler message
            buffer[n] = '\0';
            callback_(sockfd_, clientip, clientport, buffer);
        }
    }

    ~UdpServer()
    {
    }

private:
    int sockfd_;
    std::string ip_;
    uint16_t port_;
    bool isrunning_;
    func_t callback_;
};